// 模块一（服务模块）：负责启动服务
// 模块二（扩展模块）：负责扩展req和res对象，为req和res增加更好用的API.
// 模块三（路由模块）：负责进行路由判断
// 模块四（业务模块）：负责处理具体路由的业务代码
// 模块五（数据操作模块）：负责进行数据库操作
// 模块六（配置模块）：负责保存各种项目中用到的配置信息


// 1.引入http模块
const http = require('http');
const fs = require("fs"); //文件模块
const path = require("path"); //路径模块
const url = require("url"); //url模块
const querystring = require('querystring'); // 将post提交数据的查询字符串转换为json对象

// 外部模块
// mime 模块
const mime = require('mime');
const _ = require("underscore");

http.createServer(function(req, res) {
	// 路由由2中形式组成 请求方式+请求方法

	// 将render挂载到res对象上，可以通过res.render()来访问
	res.render = function(filename, tplData) {
		fs.readFile(filename, (err, data) => {
			if(err) {
				return res.end('404 Not Found!');
			} else {
				// 如果用户传递了模板数据，那么就使用underscore的template方法进行替换
				// 如果用户没有传递模板数据，那么就不进行替换
				if(tplData) {
					// 如果用户传递了模板数据，则进行模板替换
					var fn = _.template(data.toString('utf8')); // 模板字符串
					data = fn(tplData); // 将数据替换模板字符串
				}
				res.setHeader('Content-type', mime.getType(filename));
				console.log(fn);
				res.end(data);
			}
		});
	}

	req.url = req.url.toLowerCase();
	req.method = req.method.toLowerCase();

	// 通过url模块,调用url.parse()方法解析用户请求的url(req.url);
	var urlobj = url.parse(req.url, true); // 加了true后，可以把get提交的数据解析为对象，我们可以通过query.title去获取相应的数据

	if(req.url.startsWith('/resource')) {
		// 这里请求的是静态资源，静态资源直接用请求的路径拼接好
		res.render(path.join(__dirname, req.url));
	} else if(urlobj.pathname === '/item' && req.method === 'get') {
			
		readJsonData(function(list){
			// 循环list中的数据，找到和id值相等的数据
				var mode = null;
				for(var i = 0; i < list.length; i++) {
					if(list[i].id === parseInt(urlobj.query.id)) {
						mode = list[i];
						break;
					}
				}

				if(mode) {
					// 3调用res.render函数进行模板引擎的渲染
					res.render(path.join(__dirname, 'views', 'details.html'), {list: mode});
				} else {
					res.end('No Such Item');
				}
		})
	} else if((req.url === '/' || req.url === "/index") && req.method === 'get') {

		// 封装的data.json读取文件的方法
		readJsonData(function(list) {
			res.render(path.join(__dirname, 'views', 'index.html'), {
				datalist: list
			});
		})

	} else if(req.url.startsWith('/add') && req.method === 'get') {

		readJsonData(function(list) {
			// 给新闻增加一个id属性
			urlobj.query.id = list.length;
			list.push(urlobj.query);
		})

	} else if(req.url === '/add' && req.method === 'post') {
		// 1 获取data.json中的数据
		readJsonData(function(list) {
			
		// 2 获取用户提交的数据并push到数组中去
			getPostData(req,function(postBody){
				postBody.id = list.length;
				//将用户提交到新闻push到list中
				list.push(postBody);

				// 3 将新的数据写入到data.json中				
				writeJsonData(JSON.stringify(list), function() {					
					// 重定向
					res.statusCode = 302;
					res.statusMessage = 'Found';
					res.setHeader("Location", 'index.html');
					res.end(); //每一个请求都要结束响应
				})
			})
		})
	} else {
		//		把所有要访问的页面都统一放在一个文件夹下面
		var viewsDir = path.join(__dirname, 'views');
		var filename = path.join(viewsDir, req.url);
		res.render(filename);
	}

}).listen(7070, function() {
	console.log("http://localhost:7070")
})

//封装一个render函数
//function render(filename,res){
//	fs.readFile(filename,(err,data)=>{
//		if(err){
//			return res.end('404 Not Found!');		
//		}else{
//			res.setHeader('Content-type',mime.getType(filename));
//			res.end(data);
//		}
//	})	
//}

// 封装一个读取data.json文件的函数
function readJsonData(callback) {
	fs.readFile(path.join(__dirname, 'data.json'), 'utf8', (err, data) => {

		if(err && err !== "ENOENT") {
			throw err;
		}
		var list = JSON.parse(data || '[]');

		// 异步封装中最重要的一点就是我们不能直接通过return来返回数据，要通过回调来返回数据,通过调用callback将读取的的list传出去
		callback(list);
	});
}

// 封装一个写入data.json文件的函数
function writeJsonData(data, callback){
	fs.writeFile(path.join(__dirname, 'data.json'), data, (err) => {
		if(err) {
			throw err;
		}
		// 调用callback()来执行当数据写完后执行的操作。
		callback();
	})
}

// 封装用户post提交过来的数据
function getPostData(req,callback) {
	var arr = [];
	req.on('data', function(chunk) {
		// 此处的chunk参数，就是浏览器本次提交过来的一部分数据
		// chunk的数据类型是Buffer
		arr.push(chunk);
	})

	// 监听request对象的end事件
	// 当end事件被触发的时候，表示所有数据都已经提交完毕了				
	req.on('end', function() {
		// 在这个事件中只要把arr中的所有数据都汇总起来就好了
		// 把arr中的每个buffer对象 集合起来转换为一个buffer对象
		var postBody = Buffer.concat(arr);
		// 把获取到buffter对象转换为一个字符串
		postBody = postBody.toString('utf-8');
		postBody = querystring.parse(postBody);
		
		// 通过回调把post提交过来的数据传回去
		callback(postBody);
	});
}